package com.sxj.corejava.code12_jdbc;

import com.sxj.corejava.util.DataAccessException;
import com.sxj.corejava.util.JDBCUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 石小俊
 * @date 2024年07月02日 14:43
 */
public class Test08_多表查询 {

    public static void main(String[] args) throws DataAccessException {
//        List<Emp> emps = selectAll();
//        for (Emp emp : emps) {
//            System.out.println(emp);
//        }

        Dept dept = selectById(3);
        System.out.println(dept);
    }

    /**
     * 多对一,对象属性
     * 查询所有员工以及员工所属的部门信息
     * @return
     */
    public static List<Emp> selectAll() throws DataAccessException {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<Emp> emps = new ArrayList<>();

        try {
            conn = JDBCUtil.getConnection();
            String sql = new StringBuffer()
                    .append(" select e.id,e.name,e.salary,d.id 'd.id',d.name 'd.name',d.remark ")
                    .append(" from t_emp e ")
                    .append(" left join t_dept d ")
                    .append("  on e.dept_id = d.id")
                    .toString();
            ps = conn.prepareStatement(sql);
            rs = ps.executeQuery();
            while (rs.next()) {
                // 此时结果集中的数据涉及到了两个对象Emp与Dept
                // 其中Dept是作为Emp的属性存在的
                Emp emp = new Emp();
                emp.setId(rs.getInt("id"));
                emp.setName(rs.getString("name"));
                emp.setSalary(rs.getDouble("salary"));

                // 准备一个Dept对象,接收结果集中的数据,进行映射,将结果集的字段映射到Dept对象的属性中
                Dept dept = new Dept();
                dept.setId(rs.getInt("d.id"));
                dept.setName(rs.getString("d.name"));
                dept.setRemark(rs.getString("remark"));
                // 将dept作为属性赋值给对应的Emp对象中的属性
                emp.setDept(dept);

                emps.add(emp);
            }
        } catch (DataAccessException e) {
            e.printStackTrace();
            throw e;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问异常");
        } finally {
            JDBCUtil.close(conn, ps, rs);
        }

        return emps;
    }

    /**
     * 一对多,对象集合属性
     * 根据主键查询部门以及该部门下的所有员工信息
     * @param id
     * @return
     */
    public static Dept selectById(Integer id) throws DataAccessException {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        Dept dept = null;
        try {
            conn = JDBCUtil.getConnection();
            String sql = new StringBuffer()
                    .append(" select d.id,d.name,d.remark,e.id 'e.id',e.name 'e.name',e.salary ")
                    .append(" from t_dept d ")
                    .append(" left join t_emp e ")
                    .append("   on d.id = e.dept_id ")
                    .append(" where d.id = ? ")
                    .toString();
            ps = conn.prepareStatement(sql);
            ps.setInt(1, id);
            rs = ps.executeQuery();
            while (rs.next()) {
                // 一对多映射
                // 结果集中包含了多条数据
                // 但是这些数据中,某些列的数据的值是一致的,只需要映射一次,这种数据叫做一方数据
                // 某些数据的值是不一致的,需要映射多次,这种数据叫做多方数据
                // 在对象的属性中,存在一个对象集合属性,该属性用于映射多方数据
                // 因此,映射操作存在多次,但是一方数据只映射一次,多方数据映射多次

                // 一方数据映射
                // 由于一方数据只需要映射一次,因此需要判断是否已经映射过了
                // 当dept的值为null时,说明尚未映射
                if (dept == null) {
                    dept = new Dept();
                    dept.setId(rs.getInt("id"));
                    dept.setName(rs.getString("name"));
                    dept.setRemark(rs.getString("remark"));
                }

                // 多方数据映射
                Emp emp = new Emp();
                emp.setId(rs.getInt("e.id"));
                emp.setName(rs.getString("e.name"));
                emp.setSalary(rs.getDouble("salary"));
                dept.addEmp(emp);
            }
        } catch (DataAccessException e) {
            e.printStackTrace();
            throw e;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问异常");
        } finally {
            JDBCUtil.close(conn, ps, rs);
        }

        return dept;
    }

}
